//------------------------------------------------------------------------------
#include "CPUFunction.h"
#include <stdio.h>
#include <memory.h>
//------------------------------------------------------------------------------
#define PrintHdr(str) printf("%-16s: ",#str);
//------------------------------------------------------------------------------
void TCPUFunction::PrintVendorID()
{
    PrintHdr(VendorID)
    
    (*this)(0);
    char buff[13];
    memcpy(buff  ,EBX.four,sizeof(TReg));
    memcpy(buff+4,EDX.four,sizeof(TReg));
    memcpy(buff+8,ECX.four,sizeof(TReg));
    buff[12] = 0;
    printf("%s\n",buff);
}
//------------------------------------------------------------------------------
struct TTblItem
{
    uint32_t    id;
    const char *str;
};
static TTblItem BrandTbl[] = 
{
    { 0x01, "Intel(R) Celeron(R) processor" },
    { 0x02, "Intel(R) Pentium(R) III processor" },
    { 0x03, "Intel(R) Pentium(R) III Xeon(R) processor" },
    { 0x04, "Intel(R) Pentium(R) III processor" },
    { 0x06, "Mobile Intel(R) Pentium(R) III processor-M" },
    { 0x07, "Mobile Intel(R) Celeron(R) processor" },
    { 0x08, "Intel(R) Pentium(R) 4 processor" },
    { 0x09, "Intel(R) Pentium(R) 4 processor" },
    { 0x0A, "Intel(R) Celeron(R) Processor" },
    { 0x0B, "Intel(R) Xeon(R) processor" },
    { 0x0C, "Intel(R) Xeon(R) processor MP" },
    { 0x0E, "Mobile Intel(R) Pentium(R) 4 processor–M" },
    { 0x0F, "Mobile Intel(R) Celeron(R) processor" },
    { 0x11, "Mobile Genuine Intel(R) processor" },
    { 0x12, "Intel(R) Celeron(R) M processor" },
    { 0x13, "Mobile Intel(R) Celeron(R) processor" },
    { 0x14, "Intel(R) Celeron(R) Processor" },
    { 0x15, "Mobile Genuine Intel(R) processor" },
    { 0x16, "Intel(R) Pentium(R) M processor" },
    { 0x17, "Mobile Intel(R) Celeron(R) processor" },
    { 0x00, "" }
};
//------------------------------------------------------------------------------
void TCPUFunction::PrintBrandID()
{
    PrintHdr(BrandID)
    
    (*this)(0x1);
    if (EBX.four[0] > 0)
    {
        int n=0;
        while(BrandTbl[n].id)
        {
            if (EBX.four[0] == BrandTbl[n].id)
            {
                printf("%s",BrandTbl[n].str);
                break;
            }
            n ++;
        }
    }
    printf("\n");
}
//------------------------------------------------------------------------------
void TCPUFunction::PrintBrandStr()
{
    PrintHdr(BrandStr)

    (*this)(0x80000000);
    if (EAX.full >= 0x80000004)
    {
        char buff[48];
        for(int i=0;i<3;i++)
        {
            (*this)(0x80000002+i);
            memcpy(buff+i*16   ,EAX.four,sizeof(TReg));
            memcpy(buff+i*16+ 4,EBX.four,sizeof(TReg));
            memcpy(buff+i*16+ 8,ECX.four,sizeof(TReg));
            memcpy(buff+i*16+12,EDX.four,sizeof(TReg));
        }
        printf("%s",buff);
    }
    printf("\n");
}
//------------------------------------------------------------------------------
static void PrintBinary(uint32_t n, int len)
{
    while(len)
    {
        if (n & 1)
            printf("1");
        else
            printf("0");
        
        n   >>= 1;
        len --;
    }
}
//------------------------------------------------------------------------------
#define GetBit(reg,i)      ((reg.full<<(31-i))>>31)
#define GetBits(reg,h,l)   ((reg.full<<(31-h))>>(32-(h-l+1)))
#define PrintBits(reg,h,l) PrintBinary(GetBits(reg,h,l),h-l+1);
//------------------------------------------------------------------------------
void TCPUFunction::PrintGeneral()
{
    (*this)(0x1);

    PrintHdr(Signature)
    PrintBits(EAX,27,20) printf(" ");
    PrintBits(EAX,19,16) printf(" ");
    PrintBits(EAX,13,12) printf(" ");
    PrintBits(EAX,11, 8) printf(" ");
    PrintBits(EAX, 7, 4) printf(" ");
    PrintBits(EAX, 3, 0) printf("\n");

    PrintHdr(Family)   printf("%d\n",GetBits(EAX,27,20)+GetBits(EAX,11,8));
    PrintHdr(Model)    printf("%d\n",(GetBits(EAX,19,16)<<4)+GetBits(EAX,7,4));
    PrintHdr(Stepping) printf("%d\n",GetBits(EAX,3,0));

    (*this)(0x4,0x0);
    
    PrintHdr(NumCore)   printf("%d\n",GetBits(EAX,31,26)+1);
    PrintHdr(NumThread) printf("%d\n",GetBits(EAX,25,14)+1);

    (*this)(0x80000008);

    PrintHdr(VABit) printf("%d\n",GetBits(EAX,15,8));
    PrintHdr(PABit) printf("%d\n",GetBits(EAX,7, 0));
}
//------------------------------------------------------------------------------
static TTblItem CacheTbl[] =
{
    { 0x01, "Instruction TLB: 4-KB Pages, 4-way set associative, 32 entries" },
    { 0x02, "Instruction TLB: 4-MB Pages, fully associative, 2 entries" },
    { 0x03, "Data TLB: 4-KB Pages, 4-way set associative, 64 entries" },
    { 0x04, "Data TLB: 4-MB Pages, 4-way set associative, 8 entries" },
    { 0x05, "Data TLB: 4-MB Pages, 4-way set associative, 32 entries" },
    { 0x06, "L1 instruction cache: 8-KB, 4-way set associative, 32-byte line size" },
    { 0x08, "L1 instruction cache: 16-KB, 4-way set associative, 32-byte line size" },
    { 0x09, "L1 Instruction Cache: 32-KB, 4-way set associative, 64-byte line size" },
    { 0x0A, "L1 data cache: 8-KB, 2-way set associative, 32-byte line size" },
    { 0x0B, "Instruction TLB: 4-MB pages, 4-way set associative, 4 entries" },
    { 0x0C, "L1 data cache: 16-KB, 4-way set associative, 32-byte line size" },
    { 0x0D, "L1 Data Cache: 16-KB, 4-way set associative, 64-byte line size" },
    { 0x0E, "L1 Data Cache: 24-KB, 6-way set associative, 64-byte line size" },
    { 0x21, "L2 cache: 256-KB, 8-way set associative, 64-byte line size" },
    { 0x22, "L3 cache: 512-KB, 4-way set associative, sectored cache, 64-byte line size" },
    { 0x23, "L3 cache: 1-MB, 8-way set associative, sectored cache, 64-byte line size" },
    { 0x25, "L3 cache: 2-MB, 8-way set associative, sectored cache, 64-byte line size" },
    { 0x29, "L3 cache: 4-MB, 8-way set associative, sectored cache, 64-byte line size" },
    { 0x2C, "L1 data cache: 32-KB, 8-way set associative, 64-byte line size" },
    { 0x30, "L1 instruction cache: 32-KB, 8-way set associative, 64-byte line size" },
    { 0x40, "No L2 cache or, if processor contains a valid L2 cache, no L3 cache" },
    { 0x41, "L2 cache: 128-KB, 4-way set associative, 32-byte line size" },
    { 0x42, "L2 cache: 256-KB, 4-way set associative, 32-byte line size" },
    { 0x43, "L2 cache: 512-KB, 4-way set associative, 32-byte line size" },
    { 0x44, "L2 cache: 1-MB, 4-way set associative, 32-byte line size" },
    { 0x45, "L2 cache: 2-MB, 4-way set associative, 32-byte line size" },
    { 0x46, "L3 cache: 4-MB, 4-way set associative, 64-byte line size" },
    { 0x47, "L3 cache: 8-MB, 8-way set associative, 64-byte line size" },
    { 0x48, "L2 cache: 3-MB, 12-way set associative, 64-byte line size, unified on-die" },
    { 0x49, "L2 cache: 4-MB, 16-way set associative, 64-byte line size" },
    { 0x4A, "L3 cache: 6-MB, 12-way set associative, 64-byte line size" },
    { 0x4B, "L3 cache: 8-MB, 16-way set associative, 64-byte line size" },
    { 0x4C, "L3 cache: 12-MB, 12-way set associative, 64-byte line size" },
    { 0x4D, "L3 cache: 16-MB, 16-way set associative, 64-byte line size" },
    { 0x4E, "L2 cache: 6-MB, 24-way set associative, 64-byte line size" },
    { 0x4F, "Instruction TLB: 4-KB pages, 32 entries" },
    { 0x50, "Instruction TLB: 4-KB, 2-MB or 4-MB pages, fully associative, 64 entries" },
    { 0x51, "Instruction TLB: 4-KB, 2-MB or 4-MB pages, fully associative, 128 entries" },
    { 0x52, "Instruction TLB: 4-KB, 2-MB or 4-MB pages, fully associative, 256 entries" },
    { 0x55, "Instruction TLB: 2-MB or 4-MB pages, fully associative, 7 entries" },
    { 0x56, "L1 Data TLB: 4-MB pages, 4-way set associative, 16 entries" },
    { 0x57, "L1 Data TLB: 4-KB pages, 4-way set associative, 16 entries" },
    { 0x59, "Data TLB0: 4-KB pages, fully associative, 16 entries" },
    { 0x5A, "Data TLB0: 2-MB or 4-MB pages, 4-way associative, 32 entries" },
    { 0x5B, "Data TLB: 4-KB or 4-MB pages, fully associative, 64 entries" },
    { 0x5C, "Data TLB: 4-KB or 4-MB pages, fully associative, 128 entries" },
    { 0x5D, "Data TLB: 4-KB or 4-MB pages, fully associative, 256 entries" },
    { 0x60, "L1 data cache: 16-KB, 8-way set associative, sectored cache, 64-byte line size" },
    { 0x66, "L1 data cache: 8-KB, 4-way set associative, sectored cache, 64-byte line size" },
    { 0x67, "L1 data cache: 16-KB, 4-way set associative, sectored cache, 64-byte line size" },
    { 0x68, "L1 data cache: 32-KB, 4 way set associative, sectored cache, 64-byte line size" },
    { 0x70, "Trace cache: 12K-uops, 8-way set associative" },
    { 0x71, "Trace cache: 16K-uops, 8-way set associative" },
    { 0x72, "Trace cache: 32K-uops, 8-way set associative" },
    { 0x76, "Instruction TLB: 2M/4M pages, fully associative, 8 entries" },
    { 0x78, "L2 cache: 1-MB, 4-way set associative, 64-byte line size" },
    { 0x79, "L2 cache: 128-KB, 8-way set associative, sectored cache, 64-byte line size" },
    { 0x7A, "L2 cache: 256-KB, 8-way set associative, sectored cache, 64-byte line size" },
    { 0x7B, "L2 cache: 512-KB, 8-way set associative, sectored cache, 64-byte line size" },
    { 0x7C, "L2 cache: 1-MB, 8-way set associative, sectored cache, 64-byte line size" },
    { 0x7D, "L2 cache: 2-MB, 8-way set associative, 64-byte line size" },
    { 0x7F, "L2 cache: 512-KB, 2-way set associative, 64-byte line size" },
    { 0x80, "L2 cache: 512-KB, 8-way set associative, 64-byte line size" },
    { 0x82, "L2 cache: 256-KB, 8-way set associative, 32-byte line size" },
    { 0x83, "L2 cache: 512-KB, 8-way set associative, 32-byte line size" },
    { 0x84, "L2 cache: 1-MB, 8-way set associative, 32-byte line size" },
    { 0x85, "L2 cache: 2-MB, 8-way set associative, 32-byte line size" },
    { 0x86, "L2 cache: 512-KB, 4-way set associative, 64-byte line size" },
    { 0x87, "L2 cache: 1-MB, 8-way set associative, 64-byte line size" },
    { 0xB0, "Instruction TLB: 4-KB Pages, 4-way set associative, 128 entries" },
    { 0xB1, "Instruction TLB: 2-MB pages, 4-way, 8 entries or 4M pages, 4-way, 4 entries" },
    { 0xB2, "Instruction TLB: 4-KB pages, 4-way set associative, 64 entries" },
    { 0xB3, "Data TLB: 4-KB Pages, 4-way set associative, 128 entries" },
    { 0xB4, "Data TLB: 4-KB Pages, 4-way set associative, 256 entries" },
    { 0xBA, "Data TLB: 4-KB Pages, 4-way set associative, 64 entries" },
    { 0xC0, "Data TLB: 4-KB or 4-MB Pages, 4-way set associative, 8 entries" },
    { 0xCA, "Shared L2 TLB: 4 KB pages, 4-way set associative, 512 entries" },
    { 0xD0, "L3 cache: 512-kB, 4-way set associative, 64-byte line size" },
    { 0xD1, "L3 cache: 1-MB, 4-way set associative, 64-byte line size" },
    { 0xD2, "L3 cache: 2-MB, 4-way set associative, 64-byte line size" },
    { 0xD6, "L3 cache: 1-MB, 8-way set associative, 64-byte line size" },
    { 0xD7, "L3 cache: 2-MB, 8-way set associative, 64-byte line size" },
    { 0xD8, "L3 cache: 4-MB, 8-way set associative, 64-byte line size" },
    { 0xDC, "L3 cache: 1.5-MB, 12-way set associative, 64-byte line size" },
    { 0xDD, "L3 cache: 3-MB, 12-way set associative, 64-byte line size" },
    { 0xDE, "L3 cache: 6-MB, 12-way set associative, 64-byte line size" },
    { 0xE2, "L3 cache: 2-MB, 16-way set associative, 64-byte line size" },
    { 0xE3, "L3 cache: 4-MB, 16-way set associative, 64-byte line size" },
    { 0xE4, "L3 cache: 8-MB, 16-way set associative, 64-byte line size" },
    { 0xEA, "L3 cache: 12-MB, 24-way set associative, 64-byte line size" },
    { 0xEB, "L3 cache: 18-MB, 24-way set associative, 64-byte line size" },
    { 0xEC, "L3 cache: 24-MB, 24-way set associative, 64-byte line size" },
    { 0xF0, "64-byte Prefetching" },
    { 0xF1, "128-byte Prefetching" },
    { 0x00, "" },
};
//------------------------------------------------------------------------------
#define PrintCacheStub(reg) \
    {\
        if (reg.full>>31 == 0)\
        {\
            for(int i=3;i>=0;i--)\
            {\
                if (reg.four[i] == 0)\
                continue;\
                int n=0;\
                while(CacheTbl[n].id)\
                {\
                    if (reg.four[i] == CacheTbl[n].id)\
                    {\
                        PrintHdr( ) printf("%s\n",CacheTbl[n].str);\
                        break;\
                    }\
                    n ++;\
                }\
            }\
        }\
    }
//------------------------------------------------------------------------------
void TCPUFunction::PrintCache()
{
    PrintHdr(Cache) printf("\n");

    int inx = 0;

    do
    {
        (*this)(0x4,inx);

        int type  = GetBits(EAX,4,0);

        if (type == 0)
            break;
        else
        if (type == 1)
            type = 'D';
        else
        if (type == 2)
            type = 'I';
        else
        if (type == 3)
            type = 'U';
        else
            break;

        int level = GetBits(EAX,7,5);
        int way   = GetBits(EBX,31,22)+1;
        int par   = GetBits(EBX,21,12)+1;
        int line  = GetBits(EBX,11, 0)+1;
        int set   = inx+1;
        int size  = way*par*line*set;

        PrintHdr( ) 
        printf("L%d %c %5dB %5d-way %5d-par %5dB-lsize %5d-set\n",level,type,size,way,par,line,set);
        
        inx ++;
    }
    while(1);

    (*this)(0x2);
    for(int i=0;i<EAX.four[0];i++)
        (*this)(0x2);

    PrintHdr( ) printf("\n");
    PrintCacheStub(EAX)
    PrintCacheStub(EBX)
    PrintCacheStub(ECX)
    PrintCacheStub(EDX)
}
//------------------------------------------------------------------------------
struct TFeaItem
{
    uint8_t     nBit;
    const char *Abbrev;
    const char *Desc;
};
static TFeaItem ECXFeaTbl[] =
{
    {  0, "SSE3",           "Streaming SIMD Extensions 3" },
    {  1, "PCLMULDQ",       "PCLMULDQ Instruction" },
    {  2, "DTES64",         "64-Bit Debug Store" },
    {  3, "MONITOR",        "MONITOR/MWAIT" },
    {  4, "DS-CPL",         "CPL Qualified Debug Store" },
    {  5, "VMX",            "Virtual Machine Extensions" },
    {  6, "SMX",            "Safer Mode Extensions" },
    {  7, "EIST",           "Enhanced Intel SpeedStep® Technology" },
    {  8, "TM2",            "Thermal Monitor 2" },
    {  9, "SSSE3",          "Supplemental Streaming SIMD Extensions 3" },
    { 10, "CNXT-ID",        "L1 Context ID" },
    { 12, "FMA",            "Fused Multiply Add" },
    { 13, "CX16",           "CMPXCHG16B" },
    { 14, "xTPR",           "xTPR Update Control" },
    { 15, "PDCM",           "Perfmon and Debug Capability" },
    { 17, "PCID",           "Process Context Identifiers" },
    { 18, "DCA",            "Direct Cache Access" },
    { 19, "SSE4.1",         "Streaming SIMD Extensions 4.1" },
    { 20, "SSE4.2",         "Streaming SIMD Extensions 4.2" },
    { 21, "x2APIC",         "Extended xAPIC Support" },
    { 22, "MOVBE",          "MOVBE Instruction" },
    { 23, "POPCNT",         "POPCNT Instruction" },
    { 24, "TSC-DEADLINE",   "Time Stamp Counter Deadline" },
    { 25, "AES",            "AES Instruction Extensions" },
    { 26, "XSAVE",          "XSAVE/XSTOR States" },
    { 27, "OSXSAVE",        "OS-Enabled Extended State Management" },
    { 28, "AVX",            "Advanced Vector Extensions" },
    { 29, "F16C",           "16-bit floating-point conversion instructions" },
    { 30, "RDRAND",         "RDRAND instruction supported" }
};
static TFeaItem EDXFeaTbl[] =
{
    {  0, "FPU",        "Floating-point Unit On-Chip" },
    {  1, "VME",        "Virtual Mode Extension" },
    {  2, "DE",         "Debugging Extension" },
    {  3, "PSE",        "Page Size Extension" },
    {  4, "TSC",        "Time Stamp Counter" },
    {  5, "MSR",        "Model Specific Registers" },
    {  6, "PAE",        "Physical Address Extension" },
    {  7, "MCE",        "Machine-Check Exception" },
    {  8, "CX8",        "CMPXCHG8 Instruction" },
    {  9, "APIC",       "On-chip APIC Hardware" },
    { 11, "SEP",        "Fast System Call" },
    { 12, "MTRR",       "Memory Type Range Registers" },
    { 13, "PGE",        "Page Global Enable" },
    { 14, "MCA",        "Machine-Check Architecture" },
    { 15, "CMOV",       "Conditional Move Instruction" },
    { 16, "PAT",        "Page Attribute Table" },
    { 17, "PSE-36",     "36-bit Page Size Extension" },
    { 18, "PSN",        "Processor serial number is present and enabled" },
    { 19, "CLFSH",      "CLFLUSH Instruction" },
    { 21, "DS",         "Debug Store" },
    { 22, "ACPI",       "Thermal Monitor and Software Controlled Clock Facilities" },
    { 23, "MMX",        "MMX technology" },
    { 24, "FXSR",       "FXSAVE and FXSTOR Instructions" },
    { 25, "SSE",        "Streaming SIMD Extensions" },
    { 26, "SSE2",       "Streaming SIMD Extensions 2" },
    { 27, "SS",         "Self-Snoop" },
    { 28, "HTT",        "Multi-Threading" },
    { 29, "TM",         "Thermal Monitor" },
    { 31, "PBE",        "Pending Break Enable" }
};
static TFeaItem ECXExtFeaTbl[] =
{
    {  0, "LAHF", "LAHF / SAHF" }
};
static TFeaItem EDXExtFeaTbl[] =
{
    { 29, "Intel 64",   "Intel 64 Instruction Set Architecture"},
    { 27, "RDTSCP",     "RDTSCP and IA32_TSC_AUX"},
    { 26, "1 GB Pages", "1 GB Pages"},
    { 20, "XD Bit",     "XD Bit"},
    { 11, "SYSCALL",    "SYSCALL/SYSRET"}
};
//------------------------------------------------------------------------------
#define PrintFeatureStub(reg,tbl) \
    {\
        for(int i=0;i<sizeof(tbl)/sizeof(TFeaItem);i++)\
        {\
            if (GetBit(reg,tbl[i].nBit))\
                printf(" * ");\
            else\
                printf("   ");\
            printf("%-12s : %s\n",tbl[i].Abbrev,tbl[i].Desc);\
        }\
    }
//------------------------------------------------------------------------------
void TCPUFunction::PrintFeature()
{
    PrintHdr(Features) printf("\n");

    (*this)(0x1);
    PrintFeatureStub(EDX,EDXFeaTbl)
    PrintFeatureStub(ECX,ECXFeaTbl)

    (*this)(0x80000001);
    PrintFeatureStub(ECX,ECXExtFeaTbl)
    PrintFeatureStub(EDX,EDXExtFeaTbl)
}
//------------------------------------------------------------------------------
